14장. 모르는 것에 대한 두려움

14.1 목표: 누락된 값을 구분하기

  • 테이블과 쿼리에서 NULL 값을 생산적으로 사용할 수 있는 다양한 방법이 있다.
    • 여전히 일하고 있는 직원의 퇴사일과 같이, 행을 생성할 때 값을 알 수 없는 곳에 NULL을 사용할 수 있다.
    • 전기만 사용하는 자동차에 대한 연료 효율과 같이, 주어진 칼럼이 주어진 행에서 적용 가능한 값이 없는 경우에 NULL값을 사용할 수 있다.
    • 함수에 인수로 DAY('2009-12-32')와 같이 유효하지 않은 값이 입력되는 경우 NULL을 리턴할 수 있다.
    • 외부 조인에서 매치되지 않는 행의 칼럼 값의 자리를 채우는 데 NULL 값을 사용한다.

14.2 안티패턴: NULL을 일반 값처럼 사용

  • SQL에서는 NULL을 0이나 false 또는 빈 문자열과 다른 특별한 값으로 취급한다.
    (Oracle이나 Sybase에서는 NULL이 길이가 0인 문자열과 동일 - NULL을 문자열 데이터로 취급할때)

수식에서 NULL 사용

  • NULL은 0과 같지 않다. NULL + 10 = NULL
  • 표준 SQL에서는 어떤 문자열도 NULL과 연결하면 NULL (Oracle, Sybase 예외)
  • NULL은 false와도 같지 않다.
  • NULL이 들어간 불리언 수식은 AND, OR, NOT을 사용하더라도 항상 NULL

NULL을 가질 수 있는 컬럼 검색


SELECT * FROM Bugs WHERE assigned_to = 123;

SELECT * FROM Bugs WHERE NOT (assigned_to = 123);

  • 두 쿼리 모두 assigned_to 컬럼의 값이 NULL인 행은 리턴하지 않는다.

SELECT * FROM Bugs WHERE assigned_to = NULL;

SELECT * FROM Bugs WHERE assigned_to <> NULL;

  • NULL과의 비교는 그냥 NULL.
  • 두 쿼리 모두 assigned_to 컬럼의 값이 NULL인 행을 리턴하지 않는다.

쿼리 파라미터로 NULL 사용


SELECT * FROM Bugs WHERE assigned_to = ?;

파라미터를 받는 SQL에서는 NULL을 다른 일반적인 값처럼 사용하기 어렵다. NULL을 파라미터로 사용할 수 없다.

문제 회피하기

  • NOT NULL로 선언 후 의미 없는 기본값 부여.
  • 숫자 컬럼의 경우 SUM()이나 AVG() 같은 계산시 값이 포함 된다.

14.3 안티패턴 인식 방법

  • "assigned_to 칼럼에 아무 값도 설정되지 않은 행을 어떻게 찾을 수 있지?"
  • "애플리케이션에서 몇몇 사용자의 전체 이름이 표시되지 않아. 데이터베이스에서는 분명 볼 수 있는데."
  • "이 프로젝트의 전체 작업시간 보고서에 우리가 완료한 몇몇 버그만 포함되어 있어! 그러니까 우선순위를 할당한 것들만 포함이 되어 있네"
  • "Bugs 테이블에서 '알 수 없음'을 나타내는 데 예전에 사용하던 문자열을 사용할 수 없다는 것을 확인했기 때문에,
    다른 어떤 값을 사용해야 할 지 그리고 데이터를 변환해서 우리 코드가 새로운 값을 사용하도록 하는데 개발 기간이 얼마나 필요할지 논의하기 이한 회의가 필요해."

14.4 안티패턴 사용이 합당한 경우

  • NULL을 사용하는 것은 안티패턴이 아니다. NULL을 일반적인 값처럼 사용하거나 일반적인 값을 NULL처럼 사용하는 것이 안티패턴이다.

14.5 해법: 유일한 값으로 NULL을 사용하라

스칼라 수식에서의 NULL

불리언 수식에서의 NULL

NULL 검색하기


SELECT * FROM Bugs WHERE assigned_to IS NULL;

SELECT * FROM Bugs WHERE assigned_to IS NOT NULL;

  • SQL-99 표준에서는 IS DISTINCT FROM 이란 비교연산자가 정의됨. <> 과 비슷하게 동작. 피연산자가 NULL이더라도 항상 ture 또는 false를 리턴.

SELECT * FROM Bugs WHERE assigned_to  IS NULL OR assigned_to <> 1;

SELECT * FROM Bugs WHERE assigned_to IS DISTINCT FROM 1;

code:sql}
SELECT * FROM Bugs WHERE assigned_to IS DISTINCT FROM ?;


 * 쿼리 파라미터로 리터럴 값이나 NULL을 보내고 싶을 때 이 연사자 사용.
 * PostgreSQL, IBM DB2, Firebird 지원, Oracle과 Microsoft SQL Server는 미 지원. MySQL은 전용 연산자 <=> 제공.

 h3. 컬럼을 NOT NULL로 선언하기
 * NULL 값이 애플리케이션 정책을 위반하거나 또는 의미가 없는 경우에는 컬럼에 NOT NULL 제약조건을 선언하라.
 * 필요에 따라서는 DEFAULT 값을 정의해라.

h3. 동적 디폴트
* 주어진 컬럼이나 수식에, 특히 특정 쿼리에서만 디폴트 값을 설정하는 방법이다. coalesce() 함수 사용.
(NVL() 혹은 ISNULL() 함수 사용)

Note 어떤 데이터 타입에 대해서든 누락된 값을 뜻하는데는 NULL을 사용하라.

h2. 문서에 대하여 * 최초작성일 : 2011년 12월 10일 * 이 문서는 [오라클클럽|http://www.gurubee.net] [코어 오라클 데이터베이스 스터디|7차 코어 오라클 데이터베이스 스터디] 모임에서 작성하였습니다. * {color:blue}{*}이 문서의 내용은 인사이트(insight) 에서 출간한 'SQL AntiPatterns : 개발자가 알아야 할 25가지 SQL 함정과 해법'를 참고하였습니다.*{color}